package com.example.demo.service;

import com.example.demo.domain.UserAccount;
import com.example.demo.mapper.UserAccountMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Isolation;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;

// AccountService.java
@Service
public class AccountService {

    @Autowired
    private UserAccountMapper accountMapper;



    // 🟢 场景1：可重复读（默认）—— 读一致性
    @Transactional(isolation = Isolation.REPEATABLE_READ)
    public void demonstrateRepeatableRead(Long userId) {
        // 第一次读
        UserAccount account1 = accountMapper.selectByUserId(userId);
        System.out.println("✅ 第一次读: " + account1.getBalance()); // 期望：100

        // 等待其他事务更新
        waitForDatabaseUpdate(userId,10000,200);

        // 第二次读
        UserAccount account2 = accountMapper.selectByUserId(userId);
        System.out.println("✅ 第二次读: " + account2.getBalance()); // 期望：还是 100！
    }
    // 🔵 场景2：读已提交 —— 读最新已提交数据
    @Transactional(isolation = Isolation.READ_COMMITTED)
    public void demonstrateReadCommitted(Long userId) {
        System.out.printf("🔵 场景2：读已提交 —— 读最新已提交数据%n");
        UserAccount account1 = accountMapper.selectByUserId(userId);
        System.out.println("第一次读: " + account1.getBalance()); // 100

        // 其他事务提交了新数据（balance=200）
        waitForDatabaseUpdate(userId,10000,200);


        UserAccount account2 = accountMapper.selectByUserIdWithShareLock(userId);
        System.out.println("第二次读: " + account2.getBalance()); // 可能是 200 ❗ 每次都读最新
    }

    // 🔴 场景3：防止“更新丢失”—— 强制加锁读最新
    @Transactional
    public void transferMoney(Long fromUserId, Long toUserId, BigDecimal amount) {
        // 1. 加锁读取转出账户（防止余额被并发修改）
        UserAccount fromAccount = accountMapper.selectByUserIdForUpdate(fromUserId);

        if (fromAccount.getBalance().compareTo(amount) < 0) {
            throw new RuntimeException("余额不足！");
        }

        // 2. 扣款
        fromAccount.setBalance(fromAccount.getBalance().subtract(amount));
        accountMapper.updateBalance(fromAccount);

        // 3. 入账（略）
        // ...
    }

    // 🟡 场景4：只读事务 + MVCC（适合报表）
    @Transactional(readOnly = true)
    public UserAccount getAccountSnapshot(Long userId) {
        // 利用 MVCC 快照，高并发读，不加锁
        return accountMapper.selectByUserId(userId);
    }


    /**
     * 封装一个等待函数
     * @param userId
     */
    private void waitForDatabaseUpdate(Long userId,long time,Integer newBalance) {
        try {
            System.out.println("⏳ 请在 " + time + " 秒内把 user_id=" + userId + " 的余额改成 " + newBalance + "！");
            Thread.sleep(time);
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
        }
    }
}